/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.security.logging.jul;

import org.vacoor.nothing.security.logging.CircularList;
import org.vacoor.nothing.security.logging.ListenerConfig;
import org.vacoor.nothing.security.logging.LogWatcher;
import org.vacoor.nothing.security.logging.LoggerInfo;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

//import org.apache.solr.common.SolrDocument;

public class JulWatcher extends LogWatcher<LogRecord> {

    final String name;
    RecordHandler handler = null;

    public JulWatcher(String name) {
        this.name = name;
    }

    public String getName() {
        return "JUL (" + this.name + ")";
    }

    public List<String> getAllLevels() {
        return ALL_LEVELS;
    }

    public void setLogLevel(String category, String level) {
        if ("root".equals(category)) {
            category = "";
        }

        Logger log = LogManager.getLogManager().getLogger(category);
        if ((level == null) || ("unset".equals(level)) || ("null".equals(level))) {
            if (log != null)
                log.setLevel(null);
        } else {
            if (log == null) {
                log = Logger.getLogger(category);
            }
            log.setLevel(Level.parse(level));
        }
    }

    public Collection<LoggerInfo> getAllLoggers() {
        Map map = new HashMap();
        LogManager manager = LogManager.getLogManager();

        Logger root = manager.getLogger("");

        Enumeration names = manager.getLoggerNames();
        while (names.hasMoreElements()) {
            String name = (String) names.nextElement();
            Logger logger = Logger.getLogger(name);
            if (logger != root) {
                map.put(name, new JulInfo(name, logger));
                while (true) {
                    int dot = name.lastIndexOf(".");
                    if (dot < 0) {
                        break;
                    }

                    name = name.substring(0, dot);
                    if (!map.containsKey(name)) {
                        map.put(name, new JulInfo(name, null));
                    }
                }
            }
        }
        map.put("root", new JulInfo("root", root));

        return map.values();
    }

    public void setThreshold(String level) {
        if (this.handler == null) {
            throw new IllegalStateException("Must have an handler");
        }
        this.handler.setLevel(Level.parse(level));
    }

    public String getThreshold() {
        if (this.handler == null) {
            throw new IllegalStateException("Must have an handler");
        }
        return this.handler.getLevel().toString();
    }

    public void registerListener(ListenerConfig cfg) {
        if (this.history != null) {
            throw new IllegalStateException("History already registered");
        }
        this.history = new CircularList(cfg.size);
        this.handler = new RecordHandler(this);
        if (cfg.threshold != null) {
            this.handler.setLevel(Level.parse(cfg.threshold));
        } else {
            this.handler.setLevel(Level.WARNING);
        }

        Logger log = LogManager.getLogManager().getLogger("");
        log.addHandler(this.handler);
    }

    public long getTimestamp(LogRecord event) {
        return event.getMillis();
    }

    /*
    public SolrDocument toSolrDocument(LogRecord event) {
        SolrDocument doc = new SolrDocument();
        doc.setField("time", new Date(event.getMillis()));
        doc.setField("level", event.getLevel().toString());
        doc.setField("logger", event.getLoggerName());
        doc.setField("message", event.getMessage().toString());
        Throwable t = event.getThrown();
        if (t != null) {
            doc.setField("trace", Throwables.getStackTraceAsString(t));
        }
        return doc;
    }
    */

    private static final List<String> ALL_LEVELS = Arrays.asList(new String[]{
            Level.FINEST.getName(),
            Level.FINER.getName(),
            Level.FINE.getName(),
            Level.CONFIG.getName(),
            Level.INFO.getName(),
            Level.WARNING.getName(),
            Level.SEVERE.getName(),
            Level.OFF.getName()
    });
}